home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 351-375 / disk_352 / treewalk / main.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  14KB  |  568 lines

  1. /*
  2.  * treewalk - a command to get the power of treewalk out to the CLI.
  3.  *
  4.  *    Copyright (C) 1989  Mike Meyer
  5.  *
  6.  *    This program is free software; you can redistribute it and/or modify
  7.  *    it under the terms of the GNU General Public License as published by
  8.  *    the Free Software Foundation; either version 1, or any later version.
  9.  *
  10.  *    This program is distributed in the hope that it will be useful,
  11.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *    GNU General Public License for more details.
  14.  *
  15.  *    You should have received a copy of the GNU General Public License
  16.  *    along with this program; if not, write to the Free Software
  17.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include <exec/types.h>
  21. #include <libraries/dos.h>
  22. #include <proto/dos.h>
  23. #include <proto/exec.h>
  24. #include <proto/intuition.h>
  25. #include <dos.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include "treewalk.h"
  31. #include "errors.h"
  32.  
  33. /*
  34.  * Filter parsing functions, prototypes thereof. The "void *"'s are a lie,
  35.  * but they serve their purpose.
  36.  */
  37. void *parse(char *) ;
  38. long execute(struct FileInfoBlock *, void *) ;
  39.  
  40. /* Flags needed by the visit function, to help it decide what to do */
  41. static int    singlearg = FALSE, verbose = FALSE, ignore = FALSE ;
  42. static void    *code = NULL ;
  43.  
  44. /* Things visible to other files */
  45. char    *my_name ;
  46. int    errorflag = ERROR_NONE ;
  47.  
  48. /*
  49.  * And the functions I need from below.
  50.  */
  51. static int    dofiles(long, struct FileInfoBlock *) ;
  52.  
  53. /*
  54.  * We need storage for the duration of a filter execution. We use
  55.  * the RememberKey and free it after the execution.
  56.  */
  57. static struct Remember *filterstrings = NULL ;
  58.  
  59. /*
  60.  * Things for dealing with a issuance of commands
  61.  */
  62. #define COMMAX    240    /* WShell is 240, stock would be 256 */
  63. static char    command[COMMAX] = "", *commnext = command, *commend ;
  64.  
  65. static void
  66. growcommand(char *stuff, int pad) {
  67.  
  68.     strcpy(commnext, stuff) ;
  69.     commnext += strlen(stuff) ;
  70.     if (!pad) return ;
  71.     *commnext++ = ' ' ;
  72.     *commnext = '\0' ;
  73.     }
  74.  
  75. static void
  76. endcommand(void) {
  77.  
  78.     commend = commnext ;
  79.     }
  80.  
  81. static void
  82. docommand(void) {
  83.  
  84.     if (verbose) fprintf(stderr, "Executing: %s\n", command) ;
  85.     Execute(command, NULL, Output()) ;
  86.     if (!ignore && IoErr()) {
  87.         errorflag = ERROR_WARN ;
  88.         if (verbose) fprintf(stderr, "Error from command\n") ;
  89.         else fprintf(stderr, "Error from command '%s'\n", command) ;
  90.         }
  91.     *commend = '\0' ;
  92.     commnext = commend ;
  93.     }
  94.  
  95. void
  96. main(int argc, char **argv) {
  97.     int    treeflags = TREE_PRE, stat ;
  98.     char    *rootdir = "", *filter = NULL ;
  99.     BPTR    root ;
  100.  
  101.     /* Just so we can use the Rememberkey stuff... */
  102.     if ((IntuitionBase = (struct IntuitionBase *)
  103.         OpenLibrary("intuition.library", 0L)) == NULL) {
  104.             fprintf(stderr, "%s: No intuition library!", my_name) ;
  105.             exit(RETURN_FAIL) ;
  106.             }
  107.     
  108.     my_name = argv[0] ;
  109.  
  110.     /* Argument parsing time again... */
  111.     while (*++argv)
  112.         if (!strcmp(*argv, "?")) {
  113.             fprintf(stderr, "usage: %s [options] [command]\n", my_name) ;
  114.             fprintf(stderr, "options: [post|both] [single] [verbose] [ignore] [dir <dir>] [filter <filter>] [command]\n") ;
  115.             CloseLibrary((struct Library *) IntuitionBase) ;
  116.             exit(RETURN_OK) ;
  117.             }
  118.         else if (!strnicmp(*argv, "single", 3)) singlearg = TRUE ;
  119.         else if (!strnicmp(*argv, "verbose", 3)) verbose = TRUE ;
  120.         else if (!strnicmp(*argv, "ignore", 3)) ignore = TRUE ;
  121.         else if (!strnicmp(*argv, "post", 3)) treeflags = TREE_POST ;
  122.         else if (!strnicmp(*argv, "both", 3)) treeflags = TREE_BOTH ;
  123.         else if (!strnicmp(*argv, "dir", 3)) rootdir = *++argv ;
  124.         else if (!strnicmp(*argv, "filter", 3)) filter = *++argv ;
  125.         else if (!strnicmp(*argv, "command", 3)) {
  126.             argv += 1 ;
  127.             break ;
  128.             }
  129.         else break ;    /* Start of command */
  130.  
  131.     /* Check for filter */
  132.     if (filter) {
  133.         if ((code = parse(filter)) == NULL) {
  134.             fprintf(stderr, "%s: exiting\n", my_name) ;
  135.             CloseLibrary((struct Library *) IntuitionBase) ;
  136.             exit(RETURN_ERROR) ;
  137.             }
  138.         if (filterstrings) {
  139.             FreeRemember(&filterstrings, FALSE) ;
  140.             filterstrings = NULL ;
  141.             }
  142.         }
  143.  
  144.     /*
  145.      * Now, stack up commands. Command is large enough to hold any valid
  146.      * command, so it must be large enough to hold the tail of this one.
  147.      */
  148.     while (*argv)
  149.         growcommand(*argv++, TRUE) ;
  150.     endcommand() ;
  151.  
  152.     if ((root = Lock(rootdir, ACCESS_READ)) == NULL) {
  153.         fprintf(stderr, "%s: Can't lock %s\n", my_name, rootdir) ;
  154.         CloseLibrary((struct Library *) IntuitionBase) ;
  155.         exit(RETURN_ERROR) ;
  156.         }
  157.  
  158.     treewalk(root, dofiles, treeflags) ;
  159.     UnLock(root) ;
  160.  
  161.     /* Clean up any leftover commands */
  162.     if (*commend) docommand() ;
  163.  
  164.     /* Tell the user how we exited, if need be */
  165.     switch (errorflag) {
  166.         case ERROR_BREAK: printf("*** Break: %s\n", my_name) ;
  167.         /* Fall through to next case */
  168.  
  169.         case ERROR_NONE: stat = 0;
  170.         break ;
  171.  
  172.         case ERROR_WARN: stat = RETURN_WARN ;
  173.         break ;
  174.  
  175.         case ERROR_HALT: stat = RETURN_ERROR ;
  176.         fprintf(stderr, "%s: Execution halting\n", my_name) ;
  177.         break ;
  178.         }
  179.     CloseLibrary((struct Library *) IntuitionBase) ;
  180.     exit(stat) ;
  181.     }
  182.  
  183. /*
  184.  * And now, where all the work is really done. Various things for dealing
  185.  * filtering out files, getting their true name, and building & executing
  186.  * commands.
  187.  */
  188.  
  189. /*
  190.  * pathname code: is either a valid pathname, or a "". Getpathname makes it
  191.  * hold the right thing, or return TRUE ;
  192.  */
  193. static char    pathname[FMSIZE] = "" ;
  194.  
  195. static int
  196. getpathname(BPTR lock) {
  197.  
  198.     if (getpath(lock, pathname)) {
  199.         fprintf(stderr, "%s: Failure in getting full path name!\n",
  200.             my_name) ;
  201.         *pathname = '\0' ;
  202.         errorflag = ERROR_HALT ;
  203.         return TRUE ;
  204.         }
  205.     strcat(pathname, strchr(pathname, ':') == NULL ? ":" : "/") ;
  206.     return FALSE ;
  207.     }
  208.  
  209. /*
  210.  * Some globals for use by the primitives below. The values don't change
  211.  * during one filter execution, so it don't matter much.
  212.  */
  213. static BPTR            lock_global ;
  214.  
  215. /*
  216.  * The visit function - where all the work is actually done...
  217.  */
  218. static int
  219. dofiles(BPTR lock, struct FileInfoBlock *fib) {
  220.     int    status ;
  221.  
  222.     /* First, check to see if we need to stop */
  223.     if (errorflag == ERROR_HALT) return TREE_STOP ;
  224.  
  225.     if (SetSignal(0, 0) & SIGBREAKF_CTRL_C) {
  226.         errorflag = ERROR_BREAK ;
  227.         return TREE_STOP ;
  228.         }
  229.  
  230.     /* Start a new directory */
  231.     if (fib == NULL) {
  232.         /* flush path */
  233.         pathname[0] = '\0' ;
  234.         return TREE_CONT ;
  235.         }
  236.  
  237.     /* See if we want to deal with this file */
  238.     if (code) {
  239.         lock_global = lock ;
  240.         status = !execute(fib, code) ;
  241.         if (filterstrings) {
  242.             FreeRemember(&filterstrings, TRUE) ;
  243.             filterstrings = NULL ;
  244.             }
  245.         if (status) return TREE_CONT ;
  246.         }
  247.  
  248.     /* We do, so if we don't have it yet, get it's full name */
  249.     if (!*pathname && getpathname(lock)) return TREE_STOP ;
  250.  
  251.     /* print it if nothing better to do */
  252.     if (!*command) {
  253.         printf("%s%s\n", pathname, fib->fib_FileName) ;
  254.         return TREE_CONT ;
  255.         }
  256.  
  257.     /* Deal with easy commands - just one argument! */
  258.     if (singlearg) {
  259.         growcommand("\"", FALSE) ;
  260.         growcommand(pathname, FALSE) ;
  261.         growcommand(fib->fib_FileName, FALSE) ;
  262.         growcommand("\"", FALSE) ;
  263.         docommand() ;
  264.         return TREE_CONT ;
  265.         }
  266.  
  267.     /* Otherwise, build up the command if we need to */
  268.     if (commnext - command + strlen(pathname) + strlen(fib->fib_FileName) + 3 > COMMAX)
  269.         docommand() ;
  270.     growcommand("\"", FALSE) ;
  271.     growcommand(pathname, FALSE) ;
  272.     growcommand(fib->fib_FileName, FALSE) ;
  273.     growcommand("\"", TRUE) ;
  274.     return TREE_CONT ;
  275.     }
  276.  
  277. /*
  278.  * And here we have things that check the global FIB, and extract values
  279.  * from it.
  280.  */
  281. long
  282. fibkey(struct FileInfoBlock *fib) {
  283.     return fib->fib_DiskKey ;
  284.     }
  285.  
  286. long
  287. fibdirtype(struct FileInfoBlock *fib) {
  288.     return fib->fib_DirEntryType ;
  289.     }
  290.  
  291. char *
  292. fibname(struct FileInfoBlock *fib) {
  293.     char *tmpname ;
  294.  
  295.     if ((tmpname = AllocRemember(&filterstrings, 100, 0L)) == NULL) {
  296.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  297.         errorflag = ERROR_HALT ;
  298.         return NULL ;
  299.         }
  300.     strcpy(tmpname, fib->fib_FileName) ;
  301.     strlwr(tmpname) ;
  302.     return tmpname ;
  303.     }
  304.  
  305. long
  306. fibprot(struct FileInfoBlock *fib) {
  307.     return fib->fib_Protection ^ 017 ;
  308.     }
  309.  
  310. long
  311. fibtype(struct FileInfoBlock *fib) {
  312.     return fib->fib_EntryType ;
  313.     }
  314.  
  315. long
  316. fibsize(struct FileInfoBlock *fib) {
  317.     return fib->fib_Size ;
  318.     }
  319.  
  320. long
  321. fibblock(struct FileInfoBlock *fib) {
  322.     return fib->fib_NumBlocks ;
  323.     }
  324.  
  325. long
  326. fibdate(struct FileInfoBlock *fib) {
  327.     return fib->fib_Date.ds_Days * 24 * 60 + fib->fib_Date.ds_Minute ;
  328.     }
  329.  
  330. long
  331. fibday(struct FileInfoBlock *fib) {
  332.     return fib->fib_Date.ds_Days * 24 * 60 ;
  333.     }
  334.  
  335. char *
  336. fibcomment(struct FileInfoBlock *fib) {
  337.     char *tmpname ;
  338.  
  339.     if ((tmpname = AllocRemember(&filterstrings, 80, 0L)) == NULL) {
  340.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  341.         errorflag = ERROR_HALT ;
  342.         return NULL ;
  343.         }
  344.     strcpy(tmpname, fib->fib_Comment) ;
  345.     strlwr(tmpname) ;
  346.     return tmpname ;
  347.     }
  348.  
  349. long
  350. askuser(struct FileInfoBlock *fib) {
  351.     char c ;
  352.  
  353.     if (!*pathname && getpathname(lock_global)) return 1 ;
  354.     fprintf(stderr, "%s%s? ", pathname, fib->fib_FileName) ;
  355.     fflush(stderr) ;
  356.     while ((c = getchar()) == ' ' || c == '\t')
  357.         ;
  358.     while (getchar() != '\n')
  359.         ;
  360.     return (long) (toupper(c) == 'Y') ;
  361.     }
  362.  
  363. char *
  364. fullname(struct FileInfoBlock *fib) {
  365.     char *tmpname ;
  366.  
  367.     if ((tmpname = AllocRemember(&filterstrings, FMSIZE, 0L)) == NULL) {
  368.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  369.         errorflag = ERROR_HALT ;
  370.         return NULL ;
  371.         }
  372.     if (!*pathname) getpathname(lock_global) ;
  373.     strcpy(tmpname, pathname) ;
  374.     strcat(tmpname, fib->fib_FileName) ;
  375.     strlwr(tmpname) ;
  376.     return tmpname ;
  377.     }
  378.  
  379. long
  380. isfile(struct FileInfoBlock *fib) {
  381.     return (long) (fib->fib_DirEntryType < 0) ;
  382.     }
  383.  
  384. long
  385. isdir(struct FileInfoBlock *fib) {
  386.     return (long) (fib->fib_DirEntryType >= 0) ;
  387.     }
  388.  
  389. /*
  390.  * dofib - apply one of the fibfuncs to a named file.
  391.  */
  392. long
  393. dofib(char *file, long (*func)(struct FileInfoBlock *)) {
  394.     BPTR            lock, out ;
  395.     struct FileInfoBlock    *fib ;
  396.  
  397.     if ((fib = AllocMem(sizeof(struct FileInfoBlock), 0)) == NULL) {
  398.         fprintf(stderr, "%s: Out of memory\n", my_name) ;
  399.         errorflag = ERROR_HALT ;
  400.         return 0 ;
  401.         }
  402.  
  403.     if (!(lock = Lock(file, ACCESS_READ))) {
  404.         fprintf(stderr, "%s: Can't lock %s\n", my_name, file) ;
  405.         errorflag = ERROR_HALT ;
  406.         FreeMem(fib, sizeof(*fib)) ;
  407.         return 0 ;
  408.         }
  409.  
  410.     lock_global = lock ;
  411.     *pathname = '\0' ;
  412.     if (!Examine(lock, fib)) {
  413.         fprintf(stderr, "%s: Can't examine %s\n", my_name, file) ;
  414.         errorflag = ERROR_HALT ;
  415.         UnLock(lock) ;
  416.         FreeMem(fib, sizeof(*fib)) ;
  417.         return 0 ;
  418.         }
  419.  
  420.     out = func(fib) ;
  421.     UnLock(lock) ;
  422.     FreeMem(fib, sizeof(*fib)) ;
  423.     return out ;
  424.     }
  425.  
  426. #ifndef    NO_REXX
  427. /*
  428.  * Rexx interface - for now, just feed the routine to Rexx, and return
  429.  * whatever integer it gives us back.
  430.  */
  431. #include <rexx/rxslib.h>
  432. #include <rexx/storage.h>
  433. #include <exec/ports.h>
  434.  
  435. struct Library        *RexxSysBase = NULL ;
  436. #define    REXXNAME    "ftw"
  437. void            free_code(void *) ;
  438.  
  439. long
  440. dorexx(char *macro, struct FileInfoBlock *fib) {
  441.     struct RexxMsg    *msg ;
  442.     struct MsgPort    *rexxport, *port ;
  443.     long        out ;
  444.     void        *code ;
  445.     char        result[12] ;
  446.  
  447.     /* Get the library if we need it */
  448.     if ((RexxSysBase = OpenLibrary("rexxsyslib.library", 0)) == NULL) {
  449.         fprintf(stderr, "%s: Can't open rexx library\n", my_name) ;
  450.         errorflag = ERROR_HALT ;
  451.         return 0 ;
  452.         }
  453.  
  454.     /* Create the port I use to talk to Rexx */
  455.     Forbid() ;
  456.     if (FindPort(REXXNAME) == NULL)
  457.         port = CreatePort(REXXNAME, 0) ;
  458.     Permit() ;
  459.     if (port == NULL) {
  460.         fprintf(stderr, "%s: Can't create port for rexx\n", my_name) ;
  461.         goto badnews ;
  462.         }
  463.  
  464.     /* Build the message to send */
  465.     if ((msg = CreateRexxMsg(port, REXXNAME, port->mp_Node.ln_Name)) == NULL) {
  466.         fprintf(stderr, "%s: Can't create rexx msg\n", my_name) ;
  467.         goto badnews ;
  468.         }
  469.     msg->rm_Action = RXFUNC | RXFF_RESULT | 2 ;
  470.  
  471.     /* The command & two arguments */
  472.     if (!*pathname) getpathname(lock_global) ;
  473.     msg->rm_Args[0] = macro ;
  474.     msg->rm_Args[1] = pathname ;
  475.     msg->rm_Args[2] = fib->fib_FileName ;
  476.     if (!FillRexxMsg(msg, 3, 0)) {
  477.         fprintf(stderr, "%s: Can't create rexx arguments\n", my_name) ;
  478.         DeleteRexxMsg(msg) ;
  479.         goto badnews ;
  480.         }
  481.  
  482.     /* send the message */
  483.     Forbid() ;
  484.     if (rexxport = FindPort(RXSDIR))
  485.         PutMsg(rexxport, (struct Message *) msg) ;
  486.     Permit() ;
  487.     if (!rexxport) {
  488.         fprintf(stderr, "%s: Can't find rexx port\n", my_name) ;
  489.         goto badnews ;
  490.         }
  491.  
  492.     /* Now, wait for it to come back to me */
  493.     for (;;) {
  494.         /* Get a message, and break if it's what I want */
  495.         WaitPort(port) ;
  496.         msg = (struct RexxMsg *) GetMsg(port) ;
  497.         if (msg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) break ;
  498.  
  499.         /*
  500.          * Got a command - so we interpret the "command" as a filter,
  501.          * and run it over the current fib.
  502.          */
  503.         if ((code = parse(msg->rm_Args[0])) == NULL) {
  504.             /* Didn't parse - so return "broken command string" */
  505.             msg->rm_Result1 = 10 ;
  506.             msg->rm_Result2 = 11 ;
  507.             }
  508.         else {
  509.             out = execute(fib, code) ;
  510.             free_code(code) ;
  511.             if (!(msg->rm_Action & RXFF_RESULT)) {
  512.                 /* Don't want results, so return TRUE/FALSE */
  513.                 msg->rm_Result1 = (out ? 0 : 1) ;
  514.                 msg->rm_Result2 = 0 ;
  515.                 }
  516.             else {    /* Want a result, so try and give it to them */
  517.                 sprintf(result, "%08lx", out) ;
  518.                 if ((msg->rm_Result2 =
  519.                     (LONG) CreateArgstring(result, (long) strlen(result)))
  520.                     != NULL)
  521.                     /* All ok, set result so */
  522.                     msg->rm_Result1 = 0 ;
  523.                 else {
  524.                     /* No memory, say so */
  525.                     msg->rm_Result1 = 20 ;
  526.                     msg->rm_Result2 = 3 ;
  527.                     }
  528.                 }
  529.             }
  530.         ReplyMsg((struct Message *) msg) ;
  531.         }
  532.         
  533.     /* Check the result and do what must be done */
  534.     if (msg->rm_Result1 == 0) {
  535.         out = atoi((char *) msg->rm_Result2) ;
  536.         DeleteArgstring((struct RexxArg *) msg->rm_Result2) ;
  537.         }
  538.     else {
  539.         fprintf(stderr, "%s: Rexx error: %s\n", my_name,
  540.             ErrorMsg(msg->rm_Result2)->ns_Buff) ;
  541.         goto badnews ;
  542.         }
  543.  
  544.     if (0) {    /* Make sure we execute this iff we had a problem */
  545. badnews:
  546.         errorflag = ERROR_HALT ;
  547.         out = 0 ;
  548.         }
  549.  
  550.     /* Clean up the port */
  551.     if (port != NULL) {
  552.         FreeSignal((long) (port->mp_SigBit)) ;
  553.         RemPort(port) ;
  554.         DeletePort(port) ;
  555.         }
  556.  
  557.     /* Clean up the rexx msg */
  558.     if (msg != NULL) {
  559.         ClearRexxMsg(msg, 3) ;
  560.         DeleteRexxMsg(msg) ;
  561.         }
  562.  
  563.     /* Close the library, and return */
  564.     if (RexxSysBase != NULL) CloseLibrary(RexxSysBase) ;
  565.     return out ;
  566.     }
  567. #endif
  568.